package site.teamo.biu.net.common.web.exchange;

import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.support.WebClientAdapter;
import org.springframework.web.service.invoker.HttpServiceProxyFactory;
import reactor.util.function.Tuple2;
import reactor.util.function.Tuples;
import site.teamo.biu.net.common.util.HostPort;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author haocongshun
 * @date 2023/03/07 14:05:07
 */
public class HttpExchangeContext {
    Map<HostPort, HttpServiceProxyFactory> factoryMap;

    Map<Tuple2<HostPort, Class<?>>, Object> exchangeMap;

    public HttpExchangeContext() {
        factoryMap = new ConcurrentHashMap<>();
        exchangeMap = new ConcurrentHashMap<>();
    }

    public void clear(HostPort hostPort) {
        factoryMap.remove(hostPort);
        exchangeMap.entrySet().removeIf(e -> e.getKey().getT1().equals(hostPort));
    }

    @SuppressWarnings("unchecked")
    public <T> T getExchange(HostPort hostPort, Class<T> tClass) {
        Tuple2<HostPort, Class<?>> key = Tuples.of(hostPort, tClass);
        T exchange = (T) exchangeMap.get(key);
        if (exchange == null) {
            exchange = buildExchange(key);
        }
        return exchange;
    }

    @SuppressWarnings("unchecked")
    private synchronized <T> T buildExchange(Tuple2<HostPort, Class<?>> key) {
        Object exchange = exchangeMap.get(key);
        if (exchange != null) {
            return (T) exchange;
        }
        HttpServiceProxyFactory factory = factoryMap.get(key.getT1());
        if (factory == null) {
            factory = buildFactory(key.getT1());
            factoryMap.put(key.getT1(), factory);
        }
        exchange = factory.createClient(key.getT2());
        exchangeMap.put(key, exchange);
        return (T) exchange;
    }

    private synchronized HttpServiceProxyFactory buildFactory(HostPort hostPort) {
        WebClient webClient = WebClient.builder()
                .baseUrl(hostPort.toUrl())
                .build();
        return HttpServiceProxyFactory.builder(WebClientAdapter.forClient(webClient))
                .build();
    }
}
